/**
 * 时间工具类 (兼容小程序) - 增强版
 */
class TimeUtils {
	constructor(date) {
		// 如果传入日期则使用该日期，否则使用当前日期
		this._date = date ? new Date(date) : new Date();
	}

	/**
	 * 创建 TimeUtils 实例
	 * @param {Date|string|number} date - 日期对象、日期字符串或时间戳
	 * @returns {TimeUtils} TimeUtils 实例
	 */
	static create(date) {
		return new TimeUtils(date);
	}

	/**
	 * 获取当前日期和时间
	 * @returns {Date} 当前日期时间对象
	 */
	static getCurrentTime() {
		return new Date();
	}

	/**
	 * 获取指定日期的开始时间 (00:00:00.000)
	 * @param {Date} [date=new Date()] - 指定的日期，默认为今天
	 * @returns {Date} 开始时间的 Date 对象
	 */
	static getDayStart(date = new Date()) {
		const d = new Date(date);
		d.setHours(0, 0, 0, 0);
		return d;
	}

	/**
	 * 获取指定日期的结束时间 (23:59:59.999)
	 * @param {Date} [date=new Date()] - 指定的日期，默认为今天
	 * @returns {Date} 结束时间的 Date 对象
	 */
	static getDayEnd(date = new Date()) {
		const d = new Date(date);
		d.setHours(23, 59, 59, 999);
		return d;
	}

	/**
	 * 获取当前一周的日期范围 (默认周一到周日)
	 * @param {string} [startDay='monday'] - 一周的开始是 'sunday' 还是 'monday'
	 * @returns {Object} 包含开始日期和结束日期的对象 (时间部分为当天开始)
	 */
	static getCurrentWeekRange(startDay = 'monday') {
		const now = new Date();
		// 创建副本，避免修改原始 now
		const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());

		// 获取今天是星期几 (0=Sunday, 1=Monday, ..., 6=Saturday)
		const dayOfWeek = today.getDay();

		let daysToSubtract;
		if (startDay === 'sunday') {
			// 一周从周日开始
			daysToSubtract = dayOfWeek;
		} else { // 'monday' (默认)
			daysToSubtract = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
		}

		const startDate = new Date(today);
		startDate.setDate(today.getDate() - daysToSubtract);
		// 确保开始时间是当天 00:00:00.000
		this.getDayStart(startDate);

		const endDate = new Date(startDate);
		endDate.setDate(startDate.getDate() + 6);
		// 确保结束时间是当天 23:59:59.999
		this.getDayEnd(endDate);

		return {
			start: startDate,
			end: endDate
		};
	}

	/**
	 * 获取指定日期所在一周的日期范围 (默认周一到周日)
	 * @param {Date} date - 指定的日期
	 * @param {string} [startDay='monday'] - 一周的开始是 'sunday' 还是 'monday'
	 * @returns {Object} 包含开始日期和结束日期的对象 (时间部分为当天开始)
	 */
	static getWeekRangeByDate(date, startDay = 'monday') {
		if (!(date instanceof Date)) {
			console.warn('getWeekRangeByDate: 参数不是 Date 对象');
			return null;
		}

		// 创建副本，避免修改原始 date
		const targetDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());

		// 获取今天是星期几 (0=Sunday, 1=Monday, ..., 6=Saturday)
		const dayOfWeek = targetDate.getDay();

		let daysToSubtract;
		if (startDay === 'sunday') {
			// 一周从周日开始
			daysToSubtract = dayOfWeek;
		} else { // 'monday' (默认)
			daysToSubtract = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
		}

		const startDate = new Date(targetDate);
		startDate.setDate(targetDate.getDate() - daysToSubtract);
		// 确保开始时间是当天 00:00:00.000
		this.getDayStart(startDate);

		const endDate = new Date(startDate);
		endDate.setDate(startDate.getDate() + 6);
		// 确保结束时间是当天 23:59:59.999
		let endD = this.getDayEnd(endDate);

		return {
			start: startDate,
			end: endD
		};
	}

	/**
	 * 获取当前一月的日期范围
	 * @returns {Object} 包含开始日期和结束日期的对象 (时间部分为当天开始/结束)
	 */
	static getCurrentMonthRange() {
		const now = new Date();
		const year = now.getFullYear();
		const month = now.getMonth();

		// 本月第一天
		const startDate = new Date(year, month, 1);
		this.getDayStart(startDate); // 时间设为 00:00:00.000

		// 下个月第一天
		const nextMonthFirstDay = new Date(year, month + 1, 1);
		// 本月最后一天 = 下个月第一天 - 1毫秒
		const endDate = new Date(nextMonthFirstDay.getTime() - 1);
		// 或者使用 getDayEnd: this.getDayEnd(new Date(year, month + 1, 0));
		this.getDayEnd(endDate); // 确保是 23:59:59.999

		return {
			start: startDate,
			end: endDate
		};
	}

	/**
	 * 获取指定日期所在月份的日期范围
	 * @param {Date} date - 指定的日期
	 * @returns {Object} 包含开始日期和结束日期的对象 (时间部分为当天开始/结束)
	 */
	static getMonthRangeByDate(date) {
		if (!(date instanceof Date)) {
			console.warn('getMonthRangeByDate: 参数不是 Date 对象');
			return null;
		}

		const year = date.getFullYear();
		const month = date.getMonth();

		// 本月第一天
		const startDate = new Date(year, month, 1);
		this.getDayStart(startDate); // 时间设为 00:00:00.000

		// 下个月第一天
		const nextMonthFirstDay = new Date(year, month + 1, 1);
		// 本月最后一天 = 下个月第一天 - 1毫秒
		const endDate = new Date(nextMonthFirstDay.getTime() - 1);
		// 或者使用 getDayEnd: this.getDayEnd(new Date(year, month + 1, 0));
		this.getDayEnd(endDate); // 确保是 23:59:59.999

		return {
			start: startDate,
			end: endDate
		};
	}

	/**
	 * 格式化日期为 YYYY-MM-DD 字符串
	 * @param {Date} date - 要格式化的日期对象
	 * @returns {string} 格式化后的字符串
	 */
	static formatDate(date) {
		if (!(date instanceof Date)) {
			console.warn('formatDate: 参数不是 Date 对象');
			return '';
		}
		const year = date.getFullYear();
		const month = String(date.getMonth() + 1).padStart(2, '0');
		const day = String(date.getDate()).padStart(2, '0');
		return `${year}-${month}-${day}`;
	}

	/**
	 * 格式化时间为 HH:mm:ss 字符串
	 * @param {Date} date - 要格式化的日期对象
	 * @returns {string} 格式化后的时间字符串
	 */
	static formatTime(date) {
		if (!(date instanceof Date)) {
			console.warn('formatTime: 参数不是 Date 对象');
			return '';
		}
		const hours = String(date.getHours()).padStart(2, '0');
		const minutes = String(date.getMinutes()).padStart(2, '0');
		const seconds = String(date.getSeconds()).padStart(2, '0');
		return `${hours}:${minutes}:${seconds}`;
	}

	/**
	 * 格式化日期时间为 YYYY-MM-DD HH:mm:ss 字符串
	 * @param {Date} date - 要格式化的日期对象
	 * @returns {string} 格式化后的字符串
	 */
	static formatDateTime(date) {
		return `${this.formatDate(date)} ${this.formatTime(date)}`;
	}

	/**
	 * 格式化日期时间为带毫秒的字符串 (YYYY-MM-DD HH:mm:ss.SSS)
	 * @param {Date} date - 要格式化的日期对象
	 * @returns {string} 格式化后的字符串
	 */
	static formatDateTimeWithMs(date) {
		if (!(date instanceof Date)) {
			console.warn('formatDateTimeWithMs: 参数不是 Date 对象');
			return '';
		}
		const timeStr = this.formatTime(date);
		const ms = String(date.getMilliseconds()).padStart(3, '0');
		return `${this.formatDate(date)} ${timeStr}.${ms}`;
	}

	/**
	 * 添加时间
	 * @param {number} value - 要添加的时间值
	 * @param {string} unit - 时间单位 ('years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'milliseconds')
	 * @returns {TimeUtils} 返回当前实例以支持链式调用
	 */
	add(value, unit) {
		switch (unit) {
			case 'years':
				this._date.setFullYear(this._date.getFullYear() + value);
				break;
			case 'months':
				this._date.setMonth(this._date.getMonth() + value);
				break;
			case 'weeks':
				this._date.setDate(this._date.getDate() + value * 7);
				break;
			case 'days':
				this._date.setDate(this._date.getDate() + value);
				break;
			case 'hours':
				this._date.setHours(this._date.getHours() + value);
				break;
			case 'minutes':
				this._date.setMinutes(this._date.getMinutes() + value);
				break;
			case 'seconds':
				this._date.setSeconds(this._date.getSeconds() + value);
				break;
			case 'milliseconds':
				this._date.setMilliseconds(this._date.getMilliseconds() + value);
				break;
			default:
				console.warn(`不支持的时间单位: ${unit}`);
		}
		return this;
	}

	/**
	 * 减去时间
	 * @param {number} value - 要减去的时间值
	 * @param {string} unit - 时间单位 ('years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'milliseconds')
	 * @returns {TimeUtils} 返回当前实例以支持链式调用
	 */
	subtract(value, unit) {
		return this.add(-value, unit);
	}

	/**
	 * 设置时间为当天开始 (00:00:00.000)
	 * @returns {TimeUtils} 返回当前实例以支持链式调用
	 */
	startOfDay() {
		this._date.setHours(0, 0, 0, 0);
		return this;
	}

	/**
	 * 设置时间为当天结束 (23:59:59.999)
	 * @returns {TimeUtils} 返回当前实例以支持链式调用
	 */
	endOfDay() {
		this._date.setHours(23, 59, 59, 999);
		return this;
	}

	/**
	 * 获取 Date 对象
	 * @returns {Date} Date 对象
	 */
	toDate() {
		return this._date;
	}

	/**
	 * 格式化为日期字符串 (YYYY-MM-DD)
	 * @returns {string} 格式化后的日期字符串
	 */
	formatDate() {
		return TimeUtils.formatDate(this._date);
	}

	/**
	 * 格式化为时间字符串 (HH:mm:ss)
	 * @returns {string} 格式化后的时间字符串
	 */
	formatTime() {
		return TimeUtils.formatTime(this._date);
	}

	/**
	 * 格式化为日期时间字符串 (YYYY-MM-DD HH:mm:ss)
	 * @returns {string} 格式化后的日期时间字符串
	 */
	formatDateTime() {
		return TimeUtils.formatDateTime(this._date);
	}

	/**
	 * 格式化为带毫秒的日期时间字符串 (YYYY-MM-DD HH:mm:ss.SSS)
	 * @returns {string} 格式化后的带毫秒日期时间字符串
	 */
	formatDateTimeWithMs() {
		return TimeUtils.formatDateTimeWithMs(this._date);
	}
}

// ============ 使用示例 (包含新的天开始/结束方法) ============
export {
	TimeUtils
}

// // 1. 获取当前时间
// const now = TimeUtils.getCurrentTime();
// console.log('当前时间:', TimeUtils.formatDateTimeWithMs(now));

// // 2. 获取今天开始和结束
// const todayStart = TimeUtils.getDayStart();
// const todayEnd = TimeUtils.getDayEnd();
// console.log('今天开始:', TimeUtils.formatDateTimeWithMs(todayStart)); // 例如: 2025-07-29 00:00:00.000
// console.log('今天结束:', TimeUtils.formatDateTimeWithMs(todayEnd)); // 例如: 2025-07-29 23:59:59.999

// // 3. 获取指定日期的开始和结束 (例如昨天)
// const yesterday = new Date();
// yesterday.setDate(yesterday.getDate() - 1);
// const yesterdayStart = TimeUtils.getDayStart(yesterday);
// const yesterdayEnd = TimeUtils.getDayEnd(yesterday);
// console.log('昨天开始:', TimeUtils.formatDateTimeWithMs(yesterdayStart));
// console.log('昨天结束:', TimeUtils.formatDateTimeWithMs(yesterdayEnd));

// // 4. 获取当前一周范围 (包含时间信息)
// const weekRange = TimeUtils.getCurrentWeekRange();
// console.log('本周开始:', TimeUtils.formatDateTimeWithMs(weekRange.start)); // 周一 00:00:00.000
// console.log('本周结束:', TimeUtils.formatDateTimeWithMs(weekRange.end)); // 周日 23:59:59.999

// // 5. 获取指定日期所在周范围
// const date = new Date('2025-07-15');
// const weekRangeByDate = TimeUtils.getWeekRangeByDate(date);
// console.log('指定日期所在周开始:', TimeUtils.formatDateTimeWithMs(weekRangeByDate.start));
// console.log('指定日期所在周结束:', TimeUtils.formatDateTimeWithMs(weekRangeByDate.end));

// // 6. 获取当前一月范围 (包含时间信息)
// const monthRange = TimeUtils.getCurrentMonthRange();
// console.log('本月开始:', TimeUtils.formatDateTimeWithMs(monthRange.start)); // 1号 00:00:00.000
// console.log('本月结束:', TimeUtils.formatDateTimeWithMs(monthRange.end)); // 最后一天 23:59:59.999

// // 7. 获取指定日期所在月份范围
// const date2 = new Date('2025-07-15');
// const monthRangeByDate = TimeUtils.getMonthRangeByDate(date2);
// console.log('指定日期所在月开始:', TimeUtils.formatDateTimeWithMs(monthRangeByDate.start));
// console.log('指定日期所在月结束:', TimeUtils.formatDateTimeWithMs(monthRangeByDate.end));

// // 8. 新的链式调用方式
// const date3 = TimeUtils.create().subtract(1, 'days').startOfDay().toDate();
// console.log('昨天开始:', TimeUtils.formatDateTimeWithMs(date3));

// const date4 = TimeUtils.create().add(1, 'months').subtract(1, 'days').endOfDay().formatDateTimeWithMs();
// console.log('一个月减一天的结束时间:', date4);